
#include "Random.h"
#include <System/Int32.h>
#include <System/Math.h>
#include <System/ArgumentNullException.h>

using namespace Riccsson::System;

const int Random::MBIG = Int32::MaxValue;
const int Random::MSEED = 161803398;

//---------------------------------------------------------------------------------------
void Random::init(int seed)
{
	int ii;
    int mj;
	int mk;

    // Numerical Recipes in C online @ http://www.library.cornell.edu/nr/bookcpdf/c7-1.pdf

    if (seed == Int32::MinValue)
		mj = MSEED - Math::Abs(Int32::MinValue + 1);
    else
		mj = MSEED - Math::Abs(seed);
                        
    SeedArray[55] = mj;
    mk = 1;
    for (int i = 1; i < 55; i++)
	{
        ii = (21 * i) % 55;
        SeedArray[ii] = mk;
        mk = mj - mk;
        if (mk < 0)
                mk += MBIG;
        mj = SeedArray [ii];
    }
    for (int k = 1; k < 5; k++)
	{
        for (int i = 1; i < 56; i++)
		{
            SeedArray[i] -= SeedArray[1 + (i + 30) % 55];
            if (SeedArray[i] < 0)
                    SeedArray[i] += MBIG;
        }
    }
    inext = 0;
    inextp = 31;
}

//---------------------------------------------------------------------------------------
Random::Random()
{
	init(0);
}

//---------------------------------------------------------------------------------------
Random::Random(int Seed)
{
	init(Seed);
}

//---------------------------------------------------------------------------------------
int Random::Next()
{
	return (int)(Sample() * Int32::MaxValue);
}

//---------------------------------------------------------------------------------------
int Random::Next(int maxValue)
{
	if (maxValue < 0)
		throw ArgumentOutOfRangeException("Max value is less than min value.");

    return (int)(Sample() * maxValue);
}

//---------------------------------------------------------------------------------------
int Random::Next(int minValue, int maxValue)
{
	if (minValue > maxValue)
		throw ArgumentOutOfRangeException("Min value is greater than max value.");

    uint diff = (uint)(maxValue - minValue);
    if (diff <= 1)
		return minValue;

    return (int)((uint)(Sample() * diff) + minValue);
}

//---------------------------------------------------------------------------------------
void Random::NextBytes(Array<byte>* buffer)
{
	//if (buffer == null)
	//	throw ArgumentNullException("buffer");
	//
    //for (int i = 0; i < buffer->Length; i++)
	//{
	//	buffer [i] = (byte)(Sample() * (Byte::MaxValue + 1)); 
    //}

	throw;
}

//---------------------------------------------------------------------------------------
double Random::NextDouble()
{
	return Sample();
}

//---------------------------------------------------------------------------------------
double Random::Sample()
{
	int retVal;

    if (++inext  >= 56)
		inext  = 1;
    if (++inextp >= 56)
		inextp = 1;

    retVal = SeedArray[inext] - SeedArray[inextp];

    if (retVal < 0)
		retVal += MBIG;

    SeedArray[inext] = retVal;

    return retVal * (1.0 / MBIG);
}
